﻿#region 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using game_for_test_helper.src.helper;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using game_for_test_helper.src.util;
using SkinnedModel;
#endregion

namespace game_for_test_helper.src.graphics
{
    class SceneLoader : DrawableGameComponent
    {
        private Model model;
        private Matrix transformM;
        private bool drawMeshLine;
        private static SceneLoader globalScene;

        public SceneLoader(Game game)
            : base(game)
        {
            //transformM = Matrix.Identity * Matrix.CreateScale(10.0f) * Matrix.CreateRotationX(MathHelper.ToRadians(-90.0f)) * Matrix.CreateRotationY(MathHelper.ToRadians(180.0f));
            transformM = Matrix.Identity * Matrix.CreateScale(750.0f);
            drawMeshLine = true;
            globalScene = this;
        }

        protected override void LoadContent()
        {
            Load("scene/Easy_sense");
            base.LoadContent();
        }
        #region 碰撞地形读取与空间分割 Collision Terrian and Space Divid

        List<Triangle> TriangleList;
        List<Plane> CPlaneList;
        LineManger lm;
        private float RangeSize;
        private Vector3 BoxBegin;
        private Vector3 BoxEnd;
        private void Load(String AssetName)
        {
            model = GameStaticHolder.ContentHolder1.Load<Model>(AssetName);
            bonetranforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(bonetranforms);

            BoxBegin = new Vector3(0.0f, 0.0f, 0.0f);
            BoxEnd = new Vector3(0.0f, 0.0f, 0.0f);

            CPlaneList = new List<Plane>();
            TriangleList = new List<Triangle>();

            foreach (ModelMesh mesh in model.Meshes)
            {
                short[] indices = new short[mesh.IndexBuffer.SizeInBytes / 2];
                mesh.IndexBuffer.GetData(indices);
                VertexPositionNormalTexture[] VertexArray = new VertexPositionNormalTexture[mesh.VertexBuffer.SizeInBytes / 32];
                mesh.VertexBuffer.GetData(VertexArray);
                int ch = 0;
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    ch++;
                    int beginPosition = part.StreamOffset / part.VertexStride;
                    int beginIndex = part.BaseVertex;
                    for (int i = 0; i < part.PrimitiveCount; i++)
                    {
                        int indexpos = beginIndex + i * 3;
                        VertexPositionNormalTexture v1 = VertexArray[beginPosition + indices[indexpos]];
                        v1.Position = Vector3.Transform(v1.Position, transformM * bonetranforms[mesh.ParentBone.Index]);

                        VertexPositionNormalTexture v2 = VertexArray[beginPosition + indices[indexpos + 1]];
                        v2.Position = Vector3.Transform(v2.Position, transformM * bonetranforms[mesh.ParentBone.Index]);

                        VertexPositionNormalTexture v3 = VertexArray[beginPosition + indices[indexpos + 2]];
                        v3.Position = Vector3.Transform(v3.Position, transformM * bonetranforms[mesh.ParentBone.Index]);
                        Triangle tri = new Triangle(v1.Position, v2.Position, v3.Position);
                        TriangleList.Add(tri);
                        CPlaneList.Add(new Plane(tri.V1, tri.V2, tri.V3));

                        Vector3 v4 = Vector3.Max(v1.Position, v2.Position);
                        Vector3 v5 = Vector3.Min(v1.Position, v2.Position);

                        Vector3 V6 = Vector3.Max(v4, v3.Position);
                        Vector3 V7 = Vector3.Min(v5, v3.Position);

                        BoxBegin = Vector3.Min(BoxBegin, V6);
                        BoxEnd = Vector3.Max(BoxEnd, V7);
                    }
                }
            }
            SplitSpace();
        }
        private int WidthColumNumber = 0;
        private int HeightColumNumber = 0;
        private int LenghtColumNumber = 0;
        private Dictionary<int,List<int>> TriMap;
        public void SplitSpace()
        {
            TriMap= new Dictionary<int,List<int>>();
            LenghtColumNumber = (int)((BoxEnd.X - BoxBegin.X) / RangeSize + 1);
            HeightColumNumber = (int)((BoxEnd.Y - BoxBegin.Y) / RangeSize + 1);
            WidthColumNumber = (int)((BoxEnd.Z - BoxBegin.Z) / RangeSize + 1);
            int index=0;
            foreach (Triangle tri in TriangleList)
            {
                int mapcode = MapCodeGenerator(tri.V1);
                List<int> listindex;
                if (TriMap.TryGetValue(mapcode,out listindex)==false)
                {
                    listindex = new List<int>();
                    TriMap.Add(mapcode, listindex);
                }
                listindex.Add(index);
                index++;
            }
        }
        private int MapCodeGenerator(Vector3 V)
        {
            int x = (int)(V.X / RangeSize);
            int y = (int)(V.Y / RangeSize);
            int z = (int)(V.Z / RangeSize);
            int mapcode = (((y * HeightColumNumber) + z) * WidthColumNumber) + x;
            return mapcode;
        }
        #endregion
        public bool Intersect(BoundingSphere bs)
        {
            int countone = 0;
            List<int> indexlist=TriMap[MapCodeGenerator(bs.Center)];

            foreach (int indexnumber in indexlist)
            {

                Plane pl = CPlaneList[indexnumber];
                if (pl.Intersects(bs) == PlaneIntersectionType.Intersecting)
                {
                    //TextWriteHelper.StaticWrite(new Vector2(50.0f, 80.0f), "Pass 01");
                    if (SphereVtriangle(bs, pl, TriangleList[indexnumber].V1, TriangleList[indexnumber].V2, TriangleList[indexnumber].V3))
                    {
                        return true;
                    }
                }
                countone++;
            }
            return false;
        }
        private bool SphereVtriangle(BoundingSphere bs, Plane plane, Vector3 PointOne, Vector3 PointTwo, Vector3 PointThree)
        {
            Vector3 SphereCenter = bs.Center;

            float t = plane.DotNormal(PointOne - SphereCenter) / plane.Normal.LengthSquared();
            Vector3 P = plane.Normal * t + SphereCenter;
            Vector3 ab = PointOne - PointTwo;
            Vector3 bc = PointTwo - PointThree;
            Vector3 ca = PointThree - PointOne;

            Vector3 ap = PointOne - P;
            Vector3 bp = PointTwo - P;
            Vector3 cp = PointThree - P;

            float[] v = new float[3];
            v[0] = Vector3.Cross(ap, ab).Length();
            v[1] = Vector3.Cross(bp, bc).Length();
            v[2] = Vector3.Cross(cp, ca).Length();

            float sbig = Vector3.Cross(PointOne - PointTwo, PointOne - PointThree).Length();
            if (v[0] + v[1] + v[2] < sbig * 1.1)
                return true;
            return false;
        }
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            if (drawMeshLine)
            {
                lm = LineManger.GloabLineManager1;
                foreach (Triangle t in TriangleList)
                {
                    //lm.drawline(t.V1, t.V2);
                    //lm.drawline(t.V2, t.V3);
                    //lm.drawline(t.V3, t.V1);
                }
            }
        }
        private Matrix[] bonetranforms;
        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice my_device = GameStaticHolder.GraphicsDevice1;
            my_device.RenderState.AlphaBlendEnable = false;

            if (model != null)
            {
                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();
                        effect.World = transformM * bonetranforms[mesh.ParentBone.Index];
                        effect.View = SimpleCamera.ViewMatrix;
                        effect.Projection = GameStaticHolder.ProjectionMatrix;
                        //effect.TextureEnabled = true;
                    }
                    mesh.Draw();
                }
            }
            my_device.RenderState.AlphaBlendEnable = true;
            base.Draw(gameTime);
        }
        public static game_for_test_helper.src.graphics.SceneLoader GlobalScene
        {
            get { return globalScene; }
            set { globalScene = value; }
        }

    }
    class Triangle
    {
        public Triangle(Vector3 v1, Vector3 v2, Vector3 v3)
        {
            V1 = new Vector3(v1.X, v1.Y, v1.Z);
            V2 = new Vector3(v2.X, v2.Y, v2.Z);
            V3 = new Vector3(v3.X, v3.Y, v3.Z);
        }
        private Vector3 v1, v2, v3;

        public Vector3 V1
        {
            get { return v1; }
            set { v1 = value; }
        }

        public Vector3 V2
        {
            get { return v2; }
            set { v2 = value; }
        }

        public Vector3 V3
        {
            get { return v3; }
            set { v3 = value; }
        }

    }
}
